package com.atguigu.mymvc;

import com.atguigu.mymvc.util.ClassUtil;
import com.itguigu.fruit.pojo.Fruit;

import java.io.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public abstract class BaseDao<T> {
    protected  String Driver;
    protected  String URL ;
    protected  String USER;
    protected  String PWD ;

    private String entityClassName;


    public BaseDao(){
        //反射
        //this是谁？this代表的是FruitDaoImpl的实例对象
        //this。getClass（）获取的是FruitDaoImpl的class对象
        //getGenericSuperclass()获取到是：BaseDao<Fruit>
        //Type是顶层接口，表示所有的类型，他有一个子接口：ParameterizedType
        ParameterizedType genericSuperclass = (ParameterizedType)this.getClass().getGenericSuperclass();
        //Actual:实际的
        //getActualTypeArguments() 获取实际的类型参数
        Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
        Type actualTypeArgument = actualTypeArguments[0];
//        System.out.println(actualTypeArgument.getTypeName());
        entityClassName=actualTypeArgument.getTypeName();
        loadjdbcproperties();
    }
    private void loadjdbcproperties(){

        try {
//            FileReader file=
            File file = new File("D:/itguigu/pro-fruit/pro04-fruit/src/jdbc.properties");
            InputStream inputStream = new FileInputStream(file);
//            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("jdbc.properties");

//            System.out.println(inputStream);
            Properties properties = new Properties();
            properties.load(inputStream);
            Driver= properties.getProperty("jdbc.driver","com.mysql.cj.jdbc.Driver");
            URL= properties.getProperty("jdbc.url","jdbc:mysql:///fruitdb");
            USER= properties.getProperty("jdbc.user","root");
            PWD= properties.getProperty("jdbc.pwd","123456");
//            System.out.println();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
private Connection conn(){

    try {
        //1.加载驱动
        Class.forName(Driver);
        //            2.链接数据库
        return DriverManager.getConnection(URL, USER, PWD);
    } catch (ClassNotFoundException | SQLException e) {
        throw new RuntimeException(e);
    }
}
//如果是插入，就返回自增列的值
    public int update(String sql, Object... params) {
        boolean insertFlag = sql.trim().toLowerCase().startsWith("INSERT");
        Connection conn = null;
        PreparedStatement psmt = null;

        try {
            conn=conn();
//            4.psmt
            psmt =insertFlag? conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS):conn.prepareStatement(sql);
            //set
            setParams(psmt, params);

             int count= psmt.executeUpdate();
             if(insertFlag){
                 ResultSet rs = psmt.getGeneratedKeys();
                 if(rs.next()){
                     Long id = rs.getLong(1);
                     count=id.intValue();
                 }
             }
            return count;
                    

            //释放资源
        } catch ( SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                psmt.close();
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

        }

    }

    public void setParams(PreparedStatement psmt, Object... params) throws SQLException {
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                psmt.setObject(i + 1, params[i]);
            }
        }
    }

    public List<T> query(String sql, Object... params) {
//        T t = new T();
        ArrayList<T> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement psmt = null;
        ResultSet rs = null;
        try {
            conn=conn();

//            4.psmt
            psmt = conn.prepareStatement(sql);
            setParams(psmt, params);
            rs = psmt.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();//MetaData:元数据，结果集的结构数据
            while (rs.next()) {
                T t=(T)ClassUtil.createInstance(entityClassName);
                int columnCount = rsmd.getColumnCount();//获取结果集的列的数量
                for (int i = 1; i <= columnCount; i++) {
                    String ColumnLabel=rsmd.getColumnLabel(i);
                    //假设循环5次，得到5个值，对应一个对象里5个属性的值
                    Object ColumnValue = rs.getObject(i);
                    //给t这个对象的ColumnLabel属性赋ColumnValue值
                    ClassUtil.setProperty(t,ColumnLabel,ColumnValue);

                }
                list.add(t);

            }
            return list;


            //释放资源
        } catch ( SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                rs.close();
                psmt.close();
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

        }
//        return null;
    }
    public T queryByFname(String sql, Object... params) {
//        T t = new T();
//        ArrayList<T> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement psmt = null;
        ResultSet rs = null;
        try {
            conn=conn();
//            4.psmt
            psmt = conn.prepareStatement(sql);
            setParams(psmt, params);
            rs = psmt.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();//MetaData:元数据，结果集的结构数据
            if (rs.next()) {
                T t=(T) ClassUtil.createInstance(entityClassName);
                int columnCount = rsmd.getColumnCount();//获取结果集的列的数量
                for (int i = 1; i <= columnCount; i++) {
                    String ColumnLabel=rsmd.getColumnLabel(i);
                    //假设循环5次，得到5个值，对应一个对象里5个属性的值
                    Object ColumnValue = rs.getObject(i);
                    //给t这个对象的ColumnLabel属性赋ColumnValue值
                    ClassUtil.setProperty(t,ColumnLabel,ColumnValue);

                }
//                list.add(t);
                return t;

            }
            //释放资源
        } catch ( SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                rs.close();
                psmt.close();
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

        }
        return null;
    }
    public List<Object[]> CompleQuery(String sql, Object... params) {
//        T t = new T();
//        ArrayList<T> list = new ArrayList<>();
        ArrayList<Object[]> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement psmt = null;
        ResultSet rs = null;
        try {
            conn=conn();
//            4.psmt
            psmt = conn.prepareStatement(sql);
            setParams(psmt, params);
            rs = psmt.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();//MetaData:元数据，结果集的结构数据
            while (rs.next()) {
//                T t=(T)ClassUtil.createInstance(entityClassName);
                
                int columnCount = rsmd.getColumnCount();//获取结果集的列的数量
                Object[] arr = new Object[columnCount];
                for (int i = 1; i <= columnCount; i++) {
//                    String ColumnLabel=rsmd.getColumnLabel(i);
                    //假设循环5次，得到5个值，对应一个对象里5个属性的值
                    Object ColumnValue = rs.getObject(i);
                    arr[i-1]=ColumnValue;
                }
                list.add(arr);
            }
            return list;


            //释放资源
        } catch ( SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                rs.close();
                psmt.close();
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

        }
//        return null;
    }
}
